#ifndef PHYSICS_H
#define PHYSICS_H

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>

#define GLM_ENABLE_EXPERIMENTAL
#include <glm/gtx/quaternion.hpp>

#include "btBulletDynamicsCommon.h"
#include "btBulletCollisionCommon.h"

#include "BulletSoftBody/btSoftBody.h"
#include "LinearMath/btVector3.h"

#include "Core/log.h"
#include "Core/utils.h"


namespace CC
{
    // struct CollisionShape
    // {
    //     btCollisionShape *BtCollisionShape;

    //     CollisionShape(btCollisionShape *v)
    //     {
    //         BtCollisionShape = v;
    //     }
    // };

    class Entity;

    struct MyColCallBack : btCollisionWorld::ContactResultCallback
    {
    public:
        btScalar addSingleResult(
            btManifoldPoint & cp,
            const btCollisionObjectWrapper * colObj0Wrap,
            int partId0,
            int index0,
            const btCollisionObjectWrapper * colObj1Wrap,
            int partId1,
            int index1)
        {
            btVector3 posA = cp.getPositionWorldOnA();
            btVector3 posB = cp.getPositionWorldOnB();
     
            CollisionFlag = true;
            CollisionFlagOneFrame = true;
            // printf("col pos for A {%f, %f, %f %d %d}\n", posA.getX(), posA.getY(), posA.getZ(), partId0, index0);
            // printf("col pos for B {%f, %f, %f %d %d}\n", posB.getX(), posB.getY(), posB.getZ(), partId1, index1);

            return btScalar(0.f);
        };
        Entity *node0 = nullptr;
        Entity *node1 = nullptr;
        bool CollisionFlag = false;
        bool CollisionFlagOneFrame = false;
    };

    typedef enum 
    {
        RigidBodyShapeType_Box = 0,
        RigidBodyShapeType_TriangleMesh
    }RigidBodyShapeType;

    struct RigidBody
    {
        btRigidBody *BtRigidBody;        
        btCollisionShape *BtCollisionShape;

        std::vector<btRigidBody*> BtRigidBodyes;
        std::vector<btCollisionShape*> BtCollisionShapes;
        floatPtr* VertexBase = NULL;
        int* numVertices = NULL;
        uShortPtr* indexBase = NULL;
        int* numIndexes = NULL;
        void* MeshModelMaterialComponentDebug = NULL;
        void* MeshComponentDebug = NULL;

        float Mass;

        glm::vec3 BoxHalfExtents;
        glm::vec3 Transform;
        glm::vec3 Rotation;
        glm::vec3 Offset;

        glm::vec3 Scale;

        RigidBodyShapeType RigidBodyShapeTypeValue = RigidBodyShapeType_Box;

        MyColCallBack CallBack;

        RigidBody() = default;
        RigidBody(const RigidBody &) = default;

        RigidBody(btRigidBody *v, btCollisionShape *s, glm::vec3 b, glm::vec3 t, glm::vec3 o=glm::vec3(0.0), float mass = 0.0)
        {
            BtRigidBody = v;
            BtCollisionShape = s;
            BoxHalfExtents = b;
            Transform = t;            
            Offset = o;
            Mass = mass;
        }

    };

    class Physics
    {
    public:
        static RigidBody CreateShapeBox(float x, float y, float z, float mass = 0.0, glm::vec3 trans=glm::vec3(0.0), glm::vec3 rotation = glm::vec3(0.0), glm::vec3 offset = glm::vec3(0.0));
        static RigidBody CreateShapeTriangleMesh(int meshSize, floatPtr* vertexBase, int* numVertices, uShortPtr* indexBase, int* numIndexes, float mass = 0.0, 
            glm::vec3 trans=glm::vec3(0.0), glm::vec3 rotation = glm::vec3(0.0), glm::vec3 scale = glm::vec3(1.0), glm::vec3 offset = glm::vec3(0.0));
        static void SetTransform(RigidBody& rigidBody, glm::vec3 trans);
    };

}

#endif